package com.fiberhome.nas.core.util.file

import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.io.File
import java.io.RandomAccessFile
import java.util.*

/**
 * MD5计算性能测试类
 * 比较四种MD5计算方法在处理大文件时的性能
 */
class MD5PerformanceTest {
    private lateinit var testFile: File
    private val fileSize = 4L * 1024 * 1024 * 1024 // 4GB
    private val chunkSize = 1024 * 1024 // 1MB

    @Before
    fun setUp() {
        // 创建临时测试文件
        testFile = File.createTempFile("md5_test_", ".dat")
        println("创建测试文件: ${testFile.absolutePath}")

        // 生成指定大小的文件
        generateLargeFile(testFile, fileSize)
    }

    @After
    fun tearDown() {
        // 测试完成后删除测试文件
        if (testFile.exists()) {
            testFile.delete()
            println("已删除测试文件")
        }
    }

    @Test
    fun testMD5Performance() = runBlocking {
        println("开始MD5性能测试，文件大小: ${FileUtils.formatFileSize(fileSize)}")
        println("----------------------------------------")

        // 测试标准MD5计算方法
        val standardStart = System.currentTimeMillis()
        val standardMD5 = FileUtils.calculateMD5(testFile)
        val standardTime = System.currentTimeMillis() - standardStart
        println("标准MD5计算耗时: ${standardTime}ms")
        println("标准MD5结果: $standardMD5")
        println("----------------------------------------")

        // 测试优化的MD5计算方法
        val optimizedStart = System.currentTimeMillis()
        val optimizedMD5 = FileUtils.calculateOptimizedMD5(testFile)
        val optimizedTime = System.currentTimeMillis() - optimizedStart
        println("优化MD5计算耗时: ${optimizedTime}ms")
        println("优化MD5结果: $optimizedMD5")
        println("----------------------------------------")

        // 测试协程MD5计算方法
        val coroutineStart = System.currentTimeMillis()
        val coroutineMD5 = FileUtils.calculateMD5Coroutine(testFile)
        val coroutineTime = System.currentTimeMillis() - coroutineStart
        println("协程MD5计算耗时: ${coroutineTime}ms")
        println("协程MD5结果: $coroutineMD5")
        println("----------------------------------------")

        // 测试优化版协程MD5计算方法
        val coroutineV2Start = System.currentTimeMillis()
        val coroutineV2MD5 = FileUtils.getMD5CoroutineV2(testFile) { progress ->
            // 每10%输出一次进度
            if ((progress * 100).toInt() % 10 == 0) {
                println("优化版协程MD5计算进度: ${(progress * 100).toInt()}%")
            }
        }
        val coroutineV2Time = System.currentTimeMillis() - coroutineV2Start
        println("优化版协程MD5计算耗时: ${coroutineV2Time}ms")
        println("优化版协程MD5结果: $coroutineV2MD5")
        println("----------------------------------------")

        // 性能比较
        println("性能比较:")
        println("标准MD5计算耗时: ${standardTime}ms (基准)")
        println(
            "优化MD5计算耗时: ${optimizedTime}ms (${
                calculateSpeedup(
                    standardTime,
                    optimizedTime
                )
            }倍速度)"
        )
        println(
            "协程MD5计算耗时: ${coroutineTime}ms (${
                calculateSpeedup(
                    standardTime,
                    coroutineTime
                )
            }倍速度)"
        )
        println(
            "优化版协程MD5计算耗时: ${coroutineV2Time}ms (${
                calculateSpeedup(
                    standardTime,
                    coroutineV2Time
                )
            }倍速度)"
        )
        println("----------------------------------------")

        // 验证结果一致性
        println("结果一致性验证:")
        println("标准MD5与优化MD5结果一致: ${standardMD5 == optimizedMD5}")
        println("标准MD5与协程MD5结果一致: ${standardMD5 == coroutineMD5}")
        println("标准MD5与优化版协程MD5结果一致: ${standardMD5 == coroutineV2MD5}")
    }

    /**
     * 生成指定大小的测试文件
     * 使用随机数据填充文件以模拟真实场景
     */
    private fun generateLargeFile(file: File, size: Long) {
        println("开始生成测试文件，大小: ${FileUtils.formatFileSize(size)}")
        val random = Random()
        val buffer = ByteArray(chunkSize)
        val raf = RandomAccessFile(file, "rw")

        var remaining = size
        var progress = 0L
        val startTime = System.currentTimeMillis()

        while (remaining > 0) {
            // 生成随机数据
            random.nextBytes(buffer)

            // 写入数据
            val writeSize = minOf(chunkSize.toLong(), remaining)
            raf.write(buffer, 0, writeSize.toInt())

            // 更新剩余大小
            remaining -= writeSize
            progress += writeSize

            // 每生成1GB输出一次进度
            if (progress % (1024L * 1024 * 1024) == 0L) {
                val percent = (progress * 100 / size).toInt()
                println("已生成: ${FileUtils.formatFileSize(progress)} ($percent%)")
            }
        }

        raf.close()
        val totalTime = System.currentTimeMillis() - startTime
        println("测试文件生成完成，耗时: ${totalTime}ms")
    }

    /**
     * 计算性能提升倍数
     */
    private fun calculateSpeedup(baseTime: Long, optimizedTime: Long): String {
        if (optimizedTime <= 0) return "N/A"
        val speedup = baseTime.toDouble() / optimizedTime.toDouble()
        return String.format("%.2f", speedup)
    }
}